
import importlib
import inspect
import os
from typing import Dict, List, Optional, Any, Union
from .config_manager import ConfigManager, get_config_manager
from ..config.address_manager import get_device_address_manager
from .communication_manager import CommunicationManager, get_communication_manager
from .communication_interface import CommunicationInterface
from .device_interface import DeviceInterface
from ..utils.logger import get_logger
# 添加日志记录器
logger = get_logger("driver.core")


class DeviceManager:
    """设备管理器，用于管理多个设备实例（单例模式）"""

    _instance = None
    _initialized = False

    def __new__(cls, config_manager: Optional[ConfigManager] = None,
                communication_manager: Optional[CommunicationManager] = None,
                config_file: Optional[str] = None):
        """
        实现单例模式
        """
        if cls._instance is None:
            cls._instance = super(DeviceManager, cls).__new__(cls)
        return cls._instance

    def __init__(self, config_manager: Optional[ConfigManager] = None,
                 communication_manager: Optional[CommunicationManager] = None,
                 config_file: Optional[str] = None):
        """
        初始化设备管理器

        Args:
            config_manager: 配置管理器实例（可选）
            communication_manager: 通信管理器实例（可选）
            config_file: 用户配置文件路径（可选）
        """
        # 防止重复初始化
        if DeviceManager._initialized:
            return

        try:
            if config_manager:
                self.config_manager = config_manager
            else:
                # 如果没有提供配置管理器，则创建一个新的
                self.config_manager = get_config_manager(config_file)

            self.communication_manager = communication_manager or get_communication_manager(self.config_manager)
            self.devices: Dict[str, DeviceInterface] = {}
            self.device_configs: Dict[str, Dict[str, Any]] = {}

            # 初始化设备地址映射管理器
            self.device_address_manager = get_device_address_manager()

            DeviceManager._initialized = True
        except Exception as e:
            logger.error(f"DeviceManager initialization failed: {e}")
            raise

    def _parse_device_class_name(self, device_class_name: str) -> tuple:
        """
        解析设备类名，分离模块名和类名

        Args:
            device_class_name: 设备类名（格式：module.ClassName）

        Returns:
            tuple: (module_name, class_name) 元组
        """
        if '.' in device_class_name:
            module_name, class_name = device_class_name.rsplit('.', 1)
        else:
            # 如果没有指定模块，则假定在driver.device中
            # 获取当前模块的路径以支持作为第三方库使用
            current_dir = os.path.dirname(os.path.abspath(__file__))
            driver_root = os.path.dirname(current_dir)
            driver_device_path = os.path.join(driver_root, "device")

            # 检查driver.device路径是否存在
            if os.path.exists(driver_device_path):
                module_name = "driver.device"
            else:
                # 作为第三方库使用时，使用相对导入
                module_name = ".device"
            class_name = device_class_name
        return module_name, class_name

    def _create_device_instance(self, device_class_name: str, communication: CommunicationInterface, device_config: Dict[str, Any]):
        """
        根据设备类名创建设备实例

        Args:
            device_class_name: 设备类名（格式：module.ClassName）
            communication: 通信接口实例
            device_config: 设备配置信息

        Returns:
            设备实例或None（如果创建失败）
        """
        try:
            # 分离模块名和类名
            module_name, class_name = self._parse_device_class_name(device_class_name)

            # 动态导入模块
            module = importlib.import_module(module_name)

            # 获取类
            device_class = getattr(module, class_name)

            # 检查设备类的构造函数参数
            sig = inspect.signature(device_class.__init__)
            params = list(sig.parameters.keys())

            # 处理communication_address_config配置项
            address_mapping = None
            device_id = device_config.get("device_id")
            address_mapping_config_path = device_config.get("communication_address_config")

            if address_mapping_config_path:
                # 如果配置中指定了地址映射配置文件路径
                if self.device_address_manager.load_mapping_by_path(device_id, address_mapping_config_path, ""):
                    # 获取配置对象
                    address_mapping = self.device_address_manager.get_mapping(device_id, return_type="object")
            else:
                project_root =os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
                project_root = os.path.dirname(project_root)
                # 如果没有指定address_mapping_config，则加载默认配置
                if self.device_address_manager.load_default_mapping(device_id, project_root, class_name):
                    # 获取配置对象
                    address_mapping = self.device_address_manager.get_mapping(device_id, return_type="object")

            # 创建实例 - DeviceInterface只需要comm_device和address_mapping参数
            if 'address_mapping' in params:
                # 如果构造函数接受address_mapping参数
                device = device_class(communication, address_mapping)
            else:
                # 如果构造函数不接受address_mapping参数（向后兼容）
                device = device_class(communication)
            return device
        except Exception as e:
            logger.error(f"Failed to create device instance for {device_class_name}: {e}")
            return None

    def load_devices(self, protocols: Optional[List[str]] = None) -> None:
        """
        加载设备配置并创建设备实例

        Args:
            protocols: 要加载的协议列表，如果为None则加载所有协议
        """
        try:
            # 首先加载通信实例
            self.communication_manager.load_communications(protocols)

            if protocols is None:
                # 获取所有协议
                protocols = list(self.config_manager.get("devices", {}).keys())

            for protocol in protocols:
                devices_config = self.config_manager.get_devices_config(protocol)
                for device_config in devices_config:
                    device_id = device_config.get("device_id")
                    if not device_id:
                        logger.warning(f"Device config missing device_id for protocol {protocol}")
                        continue

                    try:
                        # 获取通信实例
                        communication = self.communication_manager.get_communication(device_id)
                        if not communication:
                            logger.warning(f"Communication instance not found for device {device_id}")
                            continue

                        # 根据配置创建设备实例
                        device_class_name = device_config.get("device_class")

                        # 如果配置中指定了具体的设备类，则使用该类
                        if device_class_name:
                            device = self._create_device_instance(device_class_name, communication, device_config)
                            if device:
                                # 存储设备实例和配置
                                self.devices[device_id] = device
                                self.device_configs[device_id] = device_config
                                logger.info(f"Device {device_id} loaded with class {device_class_name}")
                            else:
                                logger.error(f"Failed to create device {device_id} with class {device_class_name}")
                                continue
                        else:
                            # 如果没有指定设备类，则跳过该设备
                            logger.warning(f"No device_class specified for device {device_id}, skipping")
                            continue

                    except Exception as e:
                        logger.error(f"Failed to create device {device_id} for protocol {protocol}: {e}")
        except Exception as e:
            logger.error(f"Error loading devices: {e}")
            raise

    def get_device(self, device_id: str) -> Optional[DeviceInterface]:
        """
        获取设备实例

        Args:
            device_id: 设备ID

        Returns:
            DeviceInterface: 设备实例，如果未找到则返回None
        """
        return self.devices.get(device_id)

    def add_device(self, device_id: str, device: DeviceInterface,
                   config: Dict[str, Any]) -> bool:
        """
        添加设备实例

        Args:
            device_id: 设备ID
            device: 设备实例
            config: 设备配置

        Returns:
            bool: 是否添加成功
        """
        try:
            if device_id in self.devices:
                logger.warning(f"Device {device_id} already exists")
                return False

            self.devices[device_id] = device
            self.device_configs[device_id] = config
            logger.info(f"Device {device_id} added")
            return True
        except Exception as e:
            logger.error(f"Error adding device {device_id}: {e}")
            return False

    def remove_device(self, device_id: str) -> bool:
        """
        移除设备实例

        Args:
            device_id: 设备ID

        Returns:
            bool: 是否移除成功
        """
        try:
            if device_id not in self.devices:
                logger.warning(f"Device {device_id} not found")
                return False

            # 断开设备连接
            device = self.devices[device_id]
            try:
                device.disconnect_device()
            except Exception as e:
                logger.error(f"Error disconnecting device {device_id}: {e}")

            # 移除设备
            del self.devices[device_id]
            del self.device_configs[device_id]
            logger.info(f"Device {device_id} removed")
            return True
        except Exception as e:
            logger.error(f"Error removing device {device_id}: {e}")
            return False

    def connect_device(self, device_id: str) -> bool:
        """
        连接设备

        Args:
            device_id: 设备ID

        Returns:
            bool: 是否连接成功
        """
        try:
            device = self.devices.get(device_id)
            if not device:
                logger.error(f"Device {device_id} not found")
                return False

            result = device.connect_device()
            if result:
                logger.info(f"Device {device_id} connected")
            else:
                logger.warning(f"Device {device_id} connection failed")
            return result
        except Exception as e:
            logger.error(f"Error connecting device {device_id}: {e}")
            return False

    def disconnect_device(self, device_id: str) -> bool:
        """
        断开设备连接

        Args:
            device_id: 设备ID

        Returns:
            bool: 是否断开成功
        """
        try:
            device = self.devices.get(device_id)
            if not device:
                logger.error(f"Device {device_id} not found")
                return False

            result = device.disconnect_device()
            if result:
                logger.info(f"Device {device_id} disconnected")
            else:
                logger.warning(f"Device {device_id} disconnection failed")
            return result
        except Exception as e:
            logger.error(f"Error disconnecting device {device_id}: {e}")
            return False

    def get_all_devices(self) -> Dict[str, DeviceInterface]:
        """
        获取所有设备实例

        Returns:
            Dict[str, DeviceInterface]: 包含所有设备实例的字典副本
        """
        return self.devices.copy()

    def get_device_config(self, device_id: str) -> Optional[Dict[str, Any]]:
        """
        获取设备配置

        Args:
            device_id: 设备ID

        Returns:
            Dict[str, Any]: 对应的设备配置字典，如果未找到则返回None
        """
        return self.device_configs.get(device_id)


def get_device_manager(config_manager: Optional[ConfigManager] = None,
                       communication_manager: Optional[CommunicationManager] = None,
                       config_file: Optional[str] = None) -> "DeviceManager":
    """
    获取设备管理器实例（全局访问点）

    Args:
        config_manager: 配置管理器实例（可选）
        communication_manager: 通信管理器实例（可选）
        config_file: 配置文件路径（可选）

    Returns:
        DeviceManager: 设备管理器实例
    """
    return DeviceManager(config_manager, communication_manager, config_file)